package com.mspbots.core.wise.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mspbots.common.TimeZoneUtils;
import com.mspbots.core.AbstractBaseServiceImpl;
import com.mspbots.core.wise.mapper.TenantUserMapper;
import com.mspbots.core.wise.mapper.TenantUserTimeEntryMapper;
import com.mspbots.core.wise.model.TenantTimeEntry;
import com.mspbots.core.wise.model.TenantUser;
import com.mspbots.core.wise.model.dto.TimeEntryBotReport;
import com.mspbots.core.wise.service.TenantTimeEntryService;
import com.mspbots.cw.request.TenantTimeEntryDTO;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author David Yang
 * @date Created by 2019/6/5
 */
@Log4j2
@Service
public class TenantTimeEntryServiceImpl extends AbstractBaseServiceImpl<TenantUserTimeEntryMapper, TenantTimeEntry>
        implements TenantTimeEntryService {

    @Autowired
    private TenantUserMapper tenUserMapper;

    @Override
    public List<TenantTimeEntry> analysisList(TenantTimeEntryDTO query) {
        List<TenantTimeEntry> tenUserTimeEntryList = this.baseMapper.findAnalysisList(query);
        for (TenantTimeEntry tenUserTimeEntry : tenUserTimeEntryList) {
            QueryWrapper<TenantUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("tenant_id", tenUserTimeEntry.getTenantId());
            queryWrapper.eq("cw_uid", tenUserTimeEntry.getCwUid());
            TenantUser tenUser = tenUserMapper.selectOne(queryWrapper);
            if (tenUser != null) {
                tenUserTimeEntry.setTenantUserId(tenUser.getId());
                tenUserTimeEntry.setTenantUserName(tenUser.getFirstname() + " " + tenUser.getLastname());
            }
        }
        return tenUserTimeEntryList;
    }


    @Override
    public List<TenantTimeEntry> listbyIdAndEntrydate(TenantTimeEntryDTO query) {

        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", query.getId());
        queryWrapper.between("entered_date", LocalDateTime.of(query.getEnteredDate().toLocalDate(), LocalTime.MIN),
                LocalDateTime.of(query.getEnteredDate().toLocalDate(), LocalTime.MAX));
        List<TenantTimeEntry> tenUserTimeEntryList = this.list(queryWrapper);
        return tenUserTimeEntryList;
    }


    @Override
    public List<TenantTimeEntry> listByTenantUser(TenantTimeEntryDTO query) {
        TenantUser tenUser = tenUserMapper.selectById(query.getTenantUserId());
        if (!ObjectUtils.isEmpty(tenUser) && !ObjectUtils.isEmpty(tenUser.getCwUid())) {
            query.setCwUid(tenUser.getCwUid());
        }
        return this.baseMapper.findAnalysisList(query);
    }

    @Override
    public TenantTimeEntryDTO findLastOneById(TenantTimeEntryDTO query) {
        return this.baseMapper.findLastOneById(query);
    }

    @Override
    public Integer findByChargeToId(TenantTimeEntry query) {
        QueryWrapper<TenantTimeEntry> queryWrapper = new QueryWrapper<>(query);
        queryWrapper.eq("resolution_flag", true);
        return this.baseMapper.selectCount(queryWrapper);
    }

    @Override
    public IPage<TimeEntryBotReport> botReport(Page<TimeEntryBotReport> page, TimeEntryBotReport queryParams) {
        List<TimeEntryBotReport> list = baseMapper.botReport(page, queryParams);

        boolean isLast = true;
        if (!ObjectUtils.isEmpty(queryParams.getScriptId()) & !ObjectUtils.isEmpty(queryParams.getCwUid())) {
            AtomicReference<Integer> count = new AtomicReference<>(0);
            for (int i = list.size() - 1; i >= 0; i--) {
                if (ObjectUtils.isEmpty(list.get(i).getScriptId())) {
                    count.getAndSet(count.get() + 1);
                    list.get(i).setCount(null);
                } else {
                    if (isLast) {
                        queryParams.setTime(list.get(i).getTime());
                        LocalDateTime lastEnteredDate = baseMapper.lastEnteredDate(queryParams);
                        if (ObjectUtils.isEmpty(lastEnteredDate)) {
                            LocalDateTime currentTime = TimeZoneUtils.utcToZone(LocalDateTime.now(), "UTC").toLocalDateTime();
                            int month = getQuarterMonth(currentTime.getMonth().getValue());
                            lastEnteredDate = currentTime.withMonth(month).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);

                        }
                        queryParams.setEnteredDateStart(lastEnteredDate);
                        queryParams.setEnteredDateEnd(list.get(i).getTime());
                        log.info("last query params: {}", queryParams);
                        Integer num = baseMapper.countTimeEntryBot(queryParams);
                        log.info("last query result: {}  {}", num, list.get(i));
                        list.get(i).setCount(num);
                        isLast = false;
                    } else {
                        list.get(i).setCount(count.get());
                    }
                    count.getAndSet(0);
                }
            }
        }
        page.setRecords(list);
        return page;
    }

    @Override
    public TenantTimeEntryDTO lastOne(Long tenant) {
        TenantTimeEntry tenantUserTimeEntry = this.baseMapper.selectLastOne(tenant);
        TenantTimeEntryDTO dto = new TenantTimeEntryDTO();
        if (!ObjectUtils.isEmpty(tenantUserTimeEntry)) {
            BeanUtils.copyProperties(tenantUserTimeEntry, dto);
        }
        return dto;
    }

    private int getQuarterMonth(int value) {
        if (value <= 3) {
            return 1;
        } else if (value > 3 && value <= 6) {
            return 4;
        } else if (value > 6 && value <= 9) {
            return 7;
        } else {
            return 10;
        }
    }

}
